
/*
 * IM - Image I/O Library
 * Copyright (c) 1996 CENPES/Petrobras, TeCGraf/PUC-Rio.
 * Antonio E. Scuri - scuri@tecgraf.puc-rio.br
 * 
 * BINFILE.C
 * 
 * Contains the implementation of the I/O functions of a binary file.
 * Includes the implementation of the stream I/O functions and the memory file I/O functions.
 *
 * History:
 *          1996.12.12 - Finished inicial version.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>

#include "binfile.h"
#include "binutil.h"



/*************************************/
/* Binary File I/O, Memory functions */

typedef struct _binMemoryFile
{
  unsigned long Size;
  unsigned long MaxSize;
  unsigned char* Buffer;
  unsigned char* Ptr;
  int Error;
}binMemoryFile;


static void* binMemoryFileOpen(char* pFileName, int pWriteFlag)
{
  binMemoryFile* lNewMemHandle = (binMemoryFile*)malloc(sizeof(binMemoryFile));
  if (!lNewMemHandle)
    return NULL;

#if defined(IRIX53) || defined(IRIX62) || defined(SunOS55)
  sscanf(pFileName, "%d %d", &lNewMemHandle->Buffer, &lNewMemHandle->MaxSize);
#else
  sscanf(pFileName, "%p %d", &lNewMemHandle->Buffer, &lNewMemHandle->MaxSize);
#endif

  if (!lNewMemHandle->Buffer || !lNewMemHandle->MaxSize)
  {
    free(lNewMemHandle);
    return NULL;
  }

  if (pWriteFlag)
    lNewMemHandle->Size = 0;
  else
    lNewMemHandle->Size = lNewMemHandle->MaxSize;

  lNewMemHandle->Error = 0;
  lNewMemHandle->Ptr = lNewMemHandle->Buffer;

  return lNewMemHandle;
}/* binMemoryFileOpen */


static void binMemoryFileClose(void* pHandle)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  free(lMemHandle);
}/* binMemoryFileClose */


static unsigned long binMemoryFileSize(void* pHandle)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  return lMemHandle->Size;
}/* binMemoryFileSize */


static unsigned long binMemoryFileReadBuf(void* pHandle, unsigned char* pValues, unsigned long pSize)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  unsigned long lOffset = lMemHandle->Ptr - lMemHandle->Buffer;

  lMemHandle->Error = 0;
  if (lOffset + pSize > lMemHandle->Size)
  {
    lMemHandle->Error = 1;
    return 0;
  }

  memcpy(pValues, lMemHandle->Ptr, pSize);
  lMemHandle->Ptr += pSize;

  return pSize;
}/* binMemoryFileReadBuf */

                             
static unsigned long binMemoryFileWriteBuf(void* pHandle, unsigned char* pValues, unsigned long pSize)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  unsigned long lOffset = lMemHandle->Ptr - lMemHandle->Buffer;

  lMemHandle->Error = 0;
  if (lOffset + pSize > lMemHandle->MaxSize)
  {
    lMemHandle->Error = 1;
    return 0;
  }

  memcpy(lMemHandle->Ptr, pValues, pSize);

  if (lOffset + pSize > lMemHandle->Size)
    lMemHandle->Size = lOffset + pSize;

  lMemHandle->Ptr += pSize;

  return pSize;
}/* binMemoryFileWriteBuf */


static unsigned long binMemoryFilePrintf(void* pHandle, char *format, va_list arglist)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  unsigned long lOffset = lMemHandle->Ptr - lMemHandle->Buffer;
  unsigned long lSize = vsprintf((char*)lMemHandle->Ptr, format, arglist);

  lMemHandle->Error = 0;
  if (lOffset + lSize > lMemHandle->MaxSize)
  {
    lMemHandle->Error = 1;
    return 0;
  }

  if (lOffset + lSize > lMemHandle->Size)
    lMemHandle->Size = lOffset + lSize;

  lMemHandle->Ptr += lSize;
	return lSize;
}/* binMemoryFilePrintf */


static int binMemoryFileError(void* pHandle)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  return lMemHandle->Error;
}/* binMemoryFileError */


static void binMemoryFileSeekTo(void* pHandle, unsigned long pOffset)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;

  lMemHandle->Error = 0;
  if (pOffset > lMemHandle->MaxSize)
  {
    lMemHandle->Error = 1;
    return;
  }

  lMemHandle->Ptr = lMemHandle->Buffer + pOffset;

  if (pOffset > lMemHandle->Size)
    lMemHandle->Size = pOffset;
}/* binMemoryFileSeekTo */


static void binMemoryFileSeekFrom(void* pHandle, long pOffset)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;

  lMemHandle->Error = 0;
  if (lMemHandle->Size + pOffset > lMemHandle->MaxSize || ((long)lMemHandle->Size) + pOffset < 0)
  {
    lMemHandle->Error = 1;
    return;
  }

  lMemHandle->Ptr = lMemHandle->Buffer + lMemHandle->Size + pOffset;

  if (pOffset > 0)
    lMemHandle->Size = lMemHandle->Size + pOffset;
}/* binMemoryFileSeekFrom */


static void binMemoryFileSeekOffset(void* pHandle, long pOffset)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  long lOffset = lMemHandle->Ptr - lMemHandle->Buffer;

  lMemHandle->Error = 0;
  if (lOffset + pOffset < 0 || lOffset + pOffset > lMemHandle->MaxSize)
  {
    lMemHandle->Error = 1;
    return;
  }

  lMemHandle->Ptr += pOffset;

  if (lOffset + pOffset > lMemHandle->Size)
    lMemHandle->Size = lOffset + pOffset;
}/* binMemoryFileSeekOffset */


static unsigned long binMemoryFileTell(void* pHandle)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  unsigned long lOffset = lMemHandle->Ptr - lMemHandle->Buffer;
  return lOffset;
}/* binMemoryFileTell */


static int binMemoryFileEndOfFile(void* pHandle)
{
  binMemoryFile* lMemHandle = (binMemoryFile*)pHandle;
  unsigned long lOffset = lMemHandle->Ptr - lMemHandle->Buffer;
  return lOffset == lMemHandle->Size? 1: 0;
}/* binMemoryFileEndOfFile */


const binFileFunctionTable binMemoryFileFunctionTable = 
{
  binMemoryFileOpen,
  binMemoryFileClose,
  binMemoryFileSize,
  binMemoryFileReadBuf,
  binMemoryFileWriteBuf,
  binMemoryFilePrintf,
  binMemoryFileError, 
  binMemoryFileSeekTo, 
  binMemoryFileSeekOffset,
  binMemoryFileSeekFrom, 
  binMemoryFileTell, 
  binMemoryFileEndOfFile
};



/*************************************/
/* Binary File I/O, Stream functions */

static void* binStreamFileOpen(char* pFileName, int pWriteFlag)
{
  if (pWriteFlag)
    return fopen(pFileName, "wb");
  else
    return fopen(pFileName, "rb");
}/* binStreamFileOpen */


static void binStreamFileClose(void* pHandle)
{
  fclose((FILE*)pHandle);
}/* binStreamFileClose */


static unsigned long binStreamFileSize(void* pHandle)
{
  unsigned long lSize;
  unsigned long lCurrentPosition = ftell((FILE*)pHandle);
  fseek((FILE*)pHandle, 0L, SEEK_END);
  lSize = ftell((FILE*)pHandle) + 1L;
  fseek((FILE*)pHandle, lCurrentPosition, SEEK_SET);
  return lSize;
}/* binStreamFileSize */


static unsigned long binStreamFileReadBuf(void* pHandle, unsigned char* pValues, unsigned long pSize)
{
	return fread(pValues, 1, pSize, (FILE*)pHandle);
}/* binStreamFileReadBuf */

                             
static unsigned long binStreamFileWriteBuf(void* pHandle, unsigned char* pValues, unsigned long pSize)
{
	return fwrite(pValues, 1, pSize, (FILE*)pHandle);
}/* binStreamFileWriteBuf */


static unsigned long binStreamFilePrintf(void* pHandle, char *format, va_list arglist)
{
	return vfprintf((FILE*)pHandle, format, arglist);
}/* binStreamFilePrintf */


static int binStreamFileError(void* pHandle)
{
  return ferror((FILE*)pHandle) == 0? 0: 1;
}/* binStreamFileError */


static void binStreamFileSeekTo(void* pHandle, unsigned long pOffset)
{
  fseek((FILE*)pHandle, pOffset, SEEK_SET);
}/* binStreamFileSeekTo */


static void binStreamFileSeekOffset(void* pHandle, long pOffset)
{
  fseek((FILE*)pHandle, pOffset, SEEK_CUR);
}/* binStreamFileSeekOffset */


static void binStreamFileSeekFrom(void* pHandle, long pOffset)
{
  fseek((FILE*)pHandle, pOffset, SEEK_END);
}/* binStreamFileSeekFrom */


static unsigned long binStreamFileTell(void* pHandle)
{
  return ftell((FILE*)pHandle);
}/* binStreamFileTell */


static int binStreamFileEndOfFile(void* pHandle)
{
  return feof((FILE*)pHandle) == 0? 0: 1;
}/* binStreamFileEndOfFile */


const binFileFunctionTable binStreamFileFunctionTable = 
{
  binStreamFileOpen,
  binStreamFileClose,
  binStreamFileSize,
  binStreamFileReadBuf,
  binStreamFileWriteBuf,
  binStreamFilePrintf,
  binStreamFileError, 
  binStreamFileSeekTo, 
  binStreamFileSeekOffset,
  binStreamFileSeekFrom, 
  binStreamFileTell, 
  binStreamFileEndOfFile
};


/********************/
/* Static variables */
static int sCPUByteOrder = -1;



/*********************************************/
/* Binary File I/O, functions table handling */

static binFileFunctionTable curTable = 
{
  binStreamFileOpen,
  binStreamFileClose,
  binStreamFileSize,
  binStreamFileReadBuf,
  binStreamFileWriteBuf,
  binStreamFilePrintf,
  binStreamFileError, 
  binStreamFileSeekTo, 
  binStreamFileSeekOffset,
  binStreamFileSeekFrom, 
  binStreamFileTell, 
  binStreamFileEndOfFile
};


void binFileSetFunctionTable(binFileFunctionTable* pFunctionTable)
{
  curTable = *pFunctionTable;
}/* binFileSetFunctionTable */


void binFileSetStreamFunctionTable(void)
{
  curTable = binStreamFileFunctionTable;
}/* binFileSetStreamFunctionTable */


void binFileSetMemoryFunctionTable(void)
{
  curTable = binMemoryFileFunctionTable;
}/* binFileSetMemoryFunctionTable */



/******************************************/
/* Binary File I/O, Independent functions */

binFile* binFileOpen(char* pFileName, int pWriteFlag, int pFileByteOrder)
{
  binFile* lNewFile;

  if (sCPUByteOrder == -1)
    sCPUByteOrder = binCPUByteOrder();

  lNewFile = (binFile*)malloc(sizeof(binFile));
  if (!lNewFile)
    return NULL;

  lNewFile->Handle = curTable.Open(pFileName, pWriteFlag);
  if (!lNewFile->Handle)
  {
    free(lNewFile);
    return NULL;
  }

  lNewFile->FileByteOrder = pFileByteOrder;
  lNewFile->WriteFlag = pWriteFlag;

  return lNewFile;
}/* binFileOpen */


void binFileClose(binFile* pFile)
{
  curTable.Close(pFile->Handle);
  free(pFile);
}/* binFileClose */


unsigned long binFileSize(binFile* pFile)
{
  return curTable.Size(pFile->Handle);
}/* binFileSize */


unsigned long binFileRead1ByteBuf(binFile* pFile, unsigned char* pValues, unsigned long pSize)
{
  if (pFile->WriteFlag) return 0;
	return curTable.ReadBuf(pFile->Handle, pValues, pSize);
}/* binFileRead1ByteBuf */


unsigned long binFileRead2BytesBuf(binFile* pFile, unsigned short* pValues, unsigned long pSize)
{
  unsigned long rSize;

  if (pFile->WriteFlag) return 0;

	rSize = curTable.ReadBuf(pFile->Handle, (unsigned char*)pValues, pSize * 2);

	if (pFile->FileByteOrder != sCPUByteOrder)
	   binInvertOrder2BytesBuf(pValues, pSize);

  return rSize / 2;
}/* binFileRead2BytesBuf */


unsigned long binFileRead4BytesBuf(binFile* pFile, unsigned long* pValues, unsigned long pSize)
{
  unsigned long rSize;

  if (pFile->WriteFlag) return 0;

	rSize = curTable.ReadBuf(pFile->Handle, (unsigned char*)pValues, pSize * 4);

	if (pFile->FileByteOrder != sCPUByteOrder)
	  binInvertOrder4BytesBuf(pValues, pSize);

  return rSize / 4;
}/* binFileRead4BytesBuf */


unsigned long binFileRead8BytesBuf(binFile* pFile, double* pValues, unsigned long pSize)
{
  unsigned long rSize;

  if (pFile->WriteFlag) return 0;

	rSize = curTable.ReadBuf(pFile->Handle, (unsigned char*)pValues, pSize * 8);

	if (pFile->FileByteOrder != sCPUByteOrder)
	  binInvertOrder8BytesBuf(pValues, pSize);

  return rSize / 8;
}/* binFileRead8BytesBuf */


unsigned long binFilePrintf(binFile* pFile, char *format, ...)
{
  va_list arglist;
  va_start(arglist, format);

  if (!pFile->WriteFlag) return 0;

	return curTable.Printf(pFile->Handle, format, arglist);
}/* binFilePrintf */


unsigned long binFileWrite1ByteBuf(binFile* pFile, unsigned char* pValues, unsigned long pSize)
{
  if (!pFile->WriteFlag) return 0;
	return curTable.WriteBuf(pFile->Handle, pValues, pSize);
}/* binFileWrite1ByteBuf */


unsigned long binFileWrite2BytesBuf(binFile* pFile, unsigned short* pValues, unsigned long pSize)
{
  if (!pFile->WriteFlag) return 0;

  if (pFile->FileByteOrder != sCPUByteOrder)
		binInvertOrder2BytesBuf(pValues, pSize);

	return curTable.WriteBuf(pFile->Handle, (unsigned char*)pValues, pSize * 2) / 2;
}/* binFileWrite2BytesBuf */


unsigned long binFileWrite4BytesBuf(binFile* pFile, unsigned long* pValues, unsigned long pSize)
{
  if (!pFile->WriteFlag) return 0;

	if (pFile->FileByteOrder != sCPUByteOrder)
		binInvertOrder4BytesBuf(pValues, pSize);

	return curTable.WriteBuf(pFile->Handle, (unsigned char*)pValues, pSize * 4) / 4;
}/* binFileWrite4BytesBuf */


unsigned long binFileWrite8BytesBuf(binFile* pFile, double* pValues, unsigned long pSize)
{
  if (!pFile->WriteFlag) return 0;

	if (pFile->FileByteOrder != sCPUByteOrder)
		binInvertOrder8BytesBuf(pValues, pSize);

	return curTable.WriteBuf(pFile->Handle, (unsigned char*)pValues, pSize * 8) / 8;
}/* binFileWrite8BytesBuf */


int binFileError(binFile* pFile)
{
  return curTable.Error(pFile->Handle);
}/* binFileError */


void binFileSeekTo(binFile* pFile, unsigned long pOffset)
{
  curTable.SeekTo(pFile->Handle, pOffset);
}/* binFileSeekTo */


void binFileSeekOffset(binFile* pFile, long pOffset)
{
  curTable.SeekOffset(pFile->Handle, pOffset);
}/* binFileSeekOffset */


void binFileSeekFrom(binFile* pFile, long pOffset)
{
  curTable.SeekFrom(pFile->Handle, pOffset);
}/* binFileSeekFrom */


unsigned long binFileTell(binFile* pFile)
{
  return curTable.Tell(pFile->Handle);
}/* binFileTell */


int binFileEndOfFile(binFile* pFile)
{
  return curTable.EndOfFile(pFile->Handle);
}/* binFileEndOfFile */


/* BINFILE.C */
